<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>svg-pie</title>
</head>
<body>
	<div id="svgWrap" class="svg-wrap"></div>
	<script>
        /**
         * 将创建环图的所有操作写在drawPie函数内，配置一些默认参数
         * @param  {Element} element [插入SVG的元素，缺省直接插入到body]
         * @param  {Number}  R       [外弧起终点计算半径]
         * @param  {Number}  r       [内弧起终点计算半径]
         * @param  {Number}  width   [画布宽度]
         * @param  {Number}  height  [画布高度]
         * @param  {Array}   data    [图表数据]
         */
		function drawPie({element, R = 140, r = 100,width = 450,height = 400,data = []} = {}) {

			let w = width;
            let h = height; //将width、height赋值给w、h
            let origin = [w / 2, h / 2]; //原点坐标
            let drawData = []; //保存绘制数据，不直接修改data数组
            let sAngel = 0; //当前项的起始角度
            let eAngel = sAngel; //当前项的结束角度

            //total保存总花费,用于计算数据项占比
            let total = data.reduce(function(v, item) {
                return v + item.cost;
            }, 0)

			let svg =  createSvgTag('svg', {
				'width': w + 'px',
				'height': h + 'px',
				'viewBox': `0 0 ${w} ${h}`,		
			});

            (element && element.appendChild) ? element.appendChild(svg) : document.body.appendChild(svg);//插入到DOM

			//遍历计算每项数据
            for(let v of data) {
            	let itemData = Object.assign({}, v);//copy一遍，不直接修改原数据
            	eAngel = sAngel + v.cost / total * 2 * Math.PI; //计算结束弧度
            	itemData.arclineStarts = [
            		evaluateXY(r, sAngel, origin), //计算P0坐标
            		evaluateXY(R, sAngel, origin), //计算P1坐标 
            		evaluateXY(R, eAngel, origin), //计算P2坐标 
            		evaluateXY(r, eAngel, origin)  //计算P3坐标
            		];

            	itemData.LargeArcFlag = (eAngel - sAngel) > Math.PI ? '1' : '0'; //这个参数
            	drawData.push(itemData);//保存到drawData数据中，绘制时遍历
            	sAngel = eAngel;//将下一项数据的起始弧度设置为当前项的结束弧度
            }
            //遍历计算每项数据绘制路
            for(let v of drawData) {
            	let P = v.arclineStarts;
            	let path = createSvgTag('path', {
					'fill': v.color, //设置填充色
					'stroke': 'black',
					'stroke-width': '0', //画笔大小为零
					/**
					 * d属性设置路径字符串
					 * M ${P[0][0]} ${P[0][1]} 移动画笔到P0点
					 * L ${P[1][0]} ${P[1][1]} 绘制一条直线到P1
					 * A ${R} ${R} 0 ${v.LargeArcFlag} 1 ${P[2][0]} ${P[2][1]} 绘制外环弧到P2,R为外半径，v.LargeArcFlag画大弧还是小弧
                     * L ${P[3][0]} ${P[3][1]} 绘制一条直线到P3
                     * A ${r} ${r}  0 ${v.LargeArcFlag} 0 ${P[0][0]} ${P[0][1]} 绘制内环弧到P0点
                     * z 关闭路径
					 */
					'd': `M ${P[0][0]} ${P[0][1]} L ${P[1][0]} ${P[1][1]} A ${R} ${R} 0 ${v.LargeArcFlag} 1 ${P[2][0]} ${P[2][1]} L ${P[3][0]} ${P[3][1]} A ${r} ${r}  0 ${v.LargeArcFlag} 0 ${P[0][0]} ${P[0][1]} z`
				})
				svg.appendChild(path); //添加到画布中
            } 

			
			return svg;

			/**
			 * 计算Xy坐标
			 * @param  {[type]} r      [半径]
			 * @param  {[type]} angel  [角度]
			 * @param  {[type]} origin [原点坐标]
			 * @return {[Array]} 坐标
			 */
			function evaluateXY (r, angel, origin) {
				return [origin[0] + Math.sin(angel) * r, origin[0] - Math.cos(angel) * r]                                                                                  
			}
			/**
			 * 将创建SVG标签写成一个函数
			 * @param  {tring} tagName    [标签名]
			 * @param  {Object} attributes [标签属性]
			 * @return {Element} svg标签
			 */
			function createSvgTag (tagName, attributes) {
				let tag = document.createElementNS('http://www.w3.org/2000/svg', tagName)
				for (let attr in attributes) {
					tag.setAttribute(attr, attributes[attr])
				}
				return tag;
			}

		}
		drawPie({
			element: document.getElementById('svgWrap'),
			data: [{
                cost: 4.94,
                category: '通讯',
                color: "#e95e45",
            }, {
                cost: 4.78,
                category: '服装美容',
                color: "#20b6ab",
            }, {
                cost: 4.00,
                category: '交通出行',
                color: "#ef7340",
            }, {
                cost: 3.00,
                category: '饮食',
                color: "#eeb328",
            }, {
                cost: 49.40,
                category: '其他',
                color: "#f79954",
            }, {
                cost: 28.77,
                category: '生活日用',
                color: "#00a294",
            }]
		})
	</script>
</body>
</html>